/**
 * Copyright [2012-2013] [Guðmundur Björn Birkisson]
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. Copyright [2012-2013] [Guðmundur Björn Birkisson]
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * ---------------------------------------------------------------------------
 * 
 * Class name:  MapEditor
 * 
 * Description of class:
 * 
 * UI that allows editing of maps.
 * 
 */

package karel.editors.mapeditor;

import java.awt.Component;
import java.awt.Point;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.geom.Point2D;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.prefs.Preferences;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFormattedTextField;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;
import karel.MainWin;
import karel.editors.BasicEditor;
import karel.editors.GeneralEditor;
import karel.editors.GeneralMapEditor;
import karel.gamelogic.GameContainer;
import karel.gamelogic.GameController;
import karel.gamelogic.world.KarelMap;
import karel.gamelogic.world.KarelRobot;
import karel.gamelogic.world.Tile;
import karel.util.ClassCopier;
import karel.util.MapIO;

public class MapEditor extends javax.swing.JFrame implements BasicEditor  {
    
    private MainWin mainWin;

    private enum Tool {
        NONE, DELETE, MAKEWALL, MAKEEXIT, MAKEKAREL, MAKESTONE
    }
    
    private static final String KEY_WIN_X = "window.x";
    private static final String KEY_WIN_Y = "window.y";
    private static final String KEY_WIN_WIDTH = "window.width";
    private static final String KEY_WIN_HEIGHT = "window.height";
    
    private KarelMap karelMap;
    private KarelRobot karelRobot;
    private CommandList commandList;
    private Tool currentTool;
    private int nrOfRocks;
    private GeneralEditor ed;
    private final Preferences prefs = Preferences.userNodeForPackage(MapEditor.class);;
    
    /**
     * Simple constructor
     */
    public MapEditor() {
        initComponents();
        commonConstructor();
    }

    /**
     * Makes a MapEditor that opens a template that is a x times y map.
     * @param x
     * @param y 
     */
    public MapEditor(int x, int y) {
        initComponents();
        makeTemplate(x,y);
        commonConstructor();
        ed.askForSave();
    }
    
    /**
     * Makes a mapeditor that opens map in game container.
     * @param game 
     */
    public MapEditor(GameContainer game) {
        initComponents();
        setGameContainer(game);
        commonConstructor();
        ed.askForSave();
    }
    
    /**
     * Makes a mapeditor that opens map from file.
     * @param map 
     */
    public MapEditor(File map) {
        initComponents();
        commonConstructor();
        ed.load(map);
    }
    
    /**
     * Save window position, width, height and other variables.
     */
    private void setPref() {
        prefs.putInt(KEY_WIN_WIDTH, getWidth());
        prefs.putInt(KEY_WIN_HEIGHT, getHeight());
        prefs.putInt(KEY_WIN_X, getX());
        prefs.putInt(KEY_WIN_Y, getY());
    }

    /**
     * Load window position, width, height and other variables.
     */
    private void getPref() {
        setSize(prefs.getInt(KEY_WIN_WIDTH, getWidth()), prefs.getInt(KEY_WIN_HEIGHT, getHeight()));
        setLocation(prefs.getInt(KEY_WIN_X, getX()), prefs.getInt(KEY_WIN_Y, getY()));
    }
    
    /**
     * Initialization code that all constructors have to call.
     */
    private void commonConstructor() {
        macConstructor();
        getIcon();
        getPref();
        nrOfRocks = -1;
        ed = new GeneralMapEditor(this, this);
        newFileInit();
        
    }
    
    private void macConstructor() {
        if (System.getProperty("os.name").contains("Mac")) {
            JMenuItem openInGame = new JMenuItem();
            openInGame.setIcon(new javax.swing.ImageIcon(getClass().getResource("/editor/karelplay.png")));
            openInGame.setText("Opna borð í Leik");
            openInGame.addActionListener(new java.awt.event.ActionListener() {
                @Override
                public void actionPerformed(java.awt.event.ActionEvent evt) {
                    menuGameMousePressed(null);
                }
            });
            menuGame.add(openInGame);
        }
    }
    
    /**
     * Load the Icon for the JFrame.
     */
    private void getIcon() {
        try {
            setIconImage(ImageIO.read(getClass().getResourceAsStream("/editor/editIco.png")));
        } catch (IOException ex) {
            Logger.getLogger(MainWin.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    /**
     * Initialization code when new files are made.
     */
    private void newFileInit() {
        currentTool = Tool.NONE;
        commandList = new CommandList();
        renderer.setMap(karelMap);
        updateUI();
    }
    
    /**
     * Makes a new template of a map that is x times y big.
     * @param x
     * @param y 
     */
    private void makeTemplate(int x, int y) {
        Tile[][] data = new Tile[x][y];
        for(int i = 0; i < x; i++) {
            for(int j = 0; j < y; j++) {
                data[i][j] = i != 0 && i != x-1 && j != 0 && j != y-1 ? new Tile(Tile.Type.CLEAR) : new Tile(Tile.Type.BLOCKED);
            }
        }
        this.karelMap = new KarelMap(data, x, y);
        setKarelRobot(new KarelRobot(new Point2D.Double(1.0,1.0)));
    }
    
    /**
     * Function that is called when mousewheel is used.
     * @param x - x posiiton on maprenderer
     * @param y - x posiiton on maprenderer
     * @param increment - increment number of boxes or not.
     */
    private void performMouseWheelAction(int x, int y, boolean increment) {
        if(x == -1 || y == -1) {
            return; //Point not on the map
        }
        
        if(x == 0 || x == karelMap.WIDTH || y == 0 || y == karelMap.HEIGHT) {
            return; //Not allowed to edit edge
        }
        
        if(currentTool==Tool.MAKESTONE) {
            if(karelMap.data[x][y].getType()==Tile.Type.ROCK || karelMap.data[x][y].getType()==Tile.Type.CLEAR) {
                addCommandToList(new cChangeStone(increment,karelMap, x, y));
            }
        }
        
    }
    
    /**
     * Set the main win so mapeditor can send main win maps.
     * @param win 
     */
    public final void setMainWin(MainWin win) {
        this.mainWin = win;
    }
    
    /**
     * Loads game container to map editor.
     * @param game 
     */
    public final void setGameContainer(GameContainer game) {
        if(game!=null) {
            setKarelMap(game.map);
            setKarelRobot(game.robot);
        }
    }
    
    /**
     * Loads Karel robot into map editor.
     * @param robot 
     */
    public final void setKarelRobot(KarelRobot robot) {
        karelRobot = robot;
        renderer.setKarelRobot(robot);
    }
    
    /**
     * Loads Karel map into map editor.
     * @param map 
     */
    public final void setKarelMap(KarelMap map) {
        karelMap = map;
        renderer.setMap(map);
    }
    
    /**
     * Return Karel robot that is in the Map editor.
     * @return 
     */
    public KarelRobot getKarelRobot() {
        return karelRobot;
    }
    
    /**
     * Performs action on map according to currentTool an whether it is a left
     * or right mouse click.
     * @param x - x position on map
     * @param y - y position on map
     * @param rightButton 
     */
    private void performAction(int x, int y, boolean rightButton) {
        if(x == -1 || y == -1) {
            return; //Point not on the map
        }
        
        if(x == 0 || x == karelMap.WIDTH || y == 0 || y == karelMap.HEIGHT) {
            return; //Not allowed to edit edge
        }
        
        Tool temptl = currentTool;
        if(rightButton) {
            currentTool = Tool.DELETE;
        }
        
        switch(currentTool) {
            case DELETE:
                if(rightButton) {
                    currentTool = temptl;
                }
                if(karelMap.data[x][y].getType()!=Tile.Type.CLEAR) {
                    addCommandToList(new cDelete(karelMap, x, y));
                } else if(isKarelThere(x, y)) {
                    addCommandToList(new cMakeRobot(this, null));
                }
                break;
            case MAKEWALL:
                if(!isKarelThere(x, y)) {
                    addCommandToList(new cMakeWall(karelMap,x,y));
                }
                break;
            case MAKESTONE:
                if(getUserInput()) {
                    addCommandToList(new cMakeStone(nrOfRocks,karelMap,x,y));
                }
                break;
            case MAKEEXIT:
                addCommandToList(new cMakeExit(karelMap,x,y));
                break;
            case MAKEKAREL:
                if(!isKarelThere(x, y) && karelMap.data[x][y].getType()!=Tile.Type.BLOCKED) {
                    addCommandToList(new cMakeRobot(this, new KarelRobot(new Point2D.Double((double)x,(double)y))));
                }
                /*
                setKarelRobot(null);
                updateUI();*/
                break;
        }
    }
    
    /**
     * Called when user puts down stones.
     * @return 
     */
    private boolean getUserInput() {
        //Gera þetta function betra, initializa þetta allt í construcor
        String ok = "Í lagi";
        String cancel = "Hætta við";
        SpinnerNumberModel spinnerModel1 = new SpinnerNumberModel(nrOfRocks == -1 ? 5 : nrOfRocks, 1, 50, 1);
        JSpinner spinner1 = new JSpinner(spinnerModel1);
        
        final JFormattedTextField myTextField = ((JSpinner.DefaultEditor) spinner1.getEditor()).getTextField();
 
        myTextField.addFocusListener(new FocusAdapter() {
          public void focusGained(FocusEvent e) {
            Component c = e.getComponent();
            if (c instanceof JFormattedTextField) {
              final JFormattedTextField textField = (JFormattedTextField) c;
              SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                  textField.selectAll();
                }
              });
            }
          }
        });
        
        Object[] message = {"Fjöldi kassa?", spinner1};
        Object[] options = {ok, cancel};
        JOptionPane  optionPane = new JOptionPane(message,
                        JOptionPane.PLAIN_MESSAGE,
                         JOptionPane.OK_CANCEL_OPTION,
                          null, options);
        JDialog dialog = optionPane.createDialog(this, "Fjöldi steina?");
        
        JPanel buttonPanel = (JPanel)optionPane.getComponent(1);
        JButton buttonOk = (JButton)buttonPanel.getComponent(0);
        
        optionPane.getRootPane().setDefaultButton(buttonOk);
        
        dialog.setVisible(true);
       
        spinner1.requestFocusInWindow();
        ((JSpinner. DefaultEditor) spinner1.getEditor()).getTextField().selectAll();
        
        String value = (String)optionPane.getValue();
        if(value != null && value.equals(ok)) {
            nrOfRocks = spinnerModel1.getNumber().intValue();
            return true;
        } else {
            return false;
        }
    }
    
    /**
     * Selects newTool as currentTool.
     * @param newTool 
     */
    private void selectTool(Tool newTool) {
        currentTool = newTool;
        updateUI();
    }
    
    /**
     * Adds command c to command list.
     * @param c 
     */
    private void addCommandToList(Command c) {
        commandList.addCommand(c);
        updateUI();
    }
    
    /**
     * Updates UI according to commandlist and currentTool.
     */
    public void updateUI() {
        renderer.repaint();
        editUndo.setEnabled(commandList.canUndo());
        editRedo.setEnabled(commandList.canRedo());
        toolsDeleteObj.setEnabled(currentTool!=Tool.DELETE);
        buttonDeleteObj.setEnabled(currentTool!=Tool.DELETE);
        toolsMakeWall.setEnabled(currentTool!=Tool.MAKEWALL);
        buttonMakeWall.setEnabled(currentTool!=Tool.MAKEWALL);
        toolsMakeStone.setEnabled(currentTool!=Tool.MAKESTONE);
        buttonMakeStone.setEnabled(currentTool!=Tool.MAKESTONE);
        toolsMakeExit.setEnabled(currentTool!=Tool.MAKEEXIT);
        buttonMakeExit.setEnabled(currentTool!=Tool.MAKEEXIT);
        toolsMakeKarel.setEnabled(currentTool!=Tool.MAKEKAREL);
        buttonMakeKarel.setEnabled(currentTool!=Tool.MAKEKAREL);
        fileSaveMap.setEnabled(karelMap!=null);
        fileSaveAsMap.setEnabled(karelMap!=null);
    }
    
    /**
     * Checks if Karel is on position x,y on the map.
     * @param x
     * @param y
     * @return 
     */
    private boolean isKarelThere(int x, int y) {
        if(karelRobot == null) {
            return false;
        }
        return x == (int)karelRobot.postition.getX() && y == (int)karelRobot.postition.getY();
    }
    
    /**
     * Checks whether the map can be saved.
     * @return 
     */
    private boolean validateMap() {
        if(karelMap == null) {
            JOptionPane.showMessageDialog(this,
            "Ekkert borð opið!",
            "Villa",
            JOptionPane.ERROR_MESSAGE);
            return false;
        }
        if(karelRobot== null) {
            JOptionPane.showMessageDialog(this,
            "Karel ekki í borðinu!",
            "Villa",
            JOptionPane.ERROR_MESSAGE);
            return false;
        }
        return true;
    }
    
    /**
     * Creates a new file.
     * @return 
     */
    @Override
    public boolean newConcreteFile() {
        String ok = "Í lagi";
        String cancel = "Hætta við";
        SpinnerNumberModel spinnerModel1 = new SpinnerNumberModel(3, 3, 100, 1);
        JSpinner spinner1 = new JSpinner(spinnerModel1);
        SpinnerNumberModel spinnerModel2 = new SpinnerNumberModel(3, 3, 100, 1);
        JSpinner spinner2 = new JSpinner(spinnerModel2);
        Object[] message = {"Breidd (Minnst 3)", spinner1,"Hæð (Minnst 3)", spinner2};
        Object[] options = {ok, cancel};
        JOptionPane  optionPane = new JOptionPane(message,
                        JOptionPane.PLAIN_MESSAGE,
                         JOptionPane.OK_CANCEL_OPTION,
                          null, options);
        JDialog dialog = optionPane.createDialog(this, "Nýtt Borð!");
        dialog.setVisible(true);
        String value = (String)optionPane.getValue();
        if(value != null && value.equals(ok)) {
            makeTemplate(spinnerModel1.getNumber().intValue(),spinnerModel2.getNumber().intValue());
            newFileInit();
            return true;
        } else {
            setKarelMap(null);
            setKarelRobot(null);
            newFileInit();
            return false;
        }
    }
    
    /**
     * Saves the map to file.
     * @param file
     * @return 
     */
    @Override
    public boolean saveConcreteFile(File file) {
        try {
            MapIO.saveGame(file, new GameContainer(karelMap, karelRobot));
            return true;
        } catch(Exception e) {
            System.out.println(e);
            return false;
        }
    }

    /**
     * Loads map from file.
     * @param file
     * @return 
     */
    @Override
    public boolean loadConcreteFile(File file) {
        try {
            GameContainer g = MapIO.loadGame(file);
            setKarelMap(g.map);
            setKarelRobot(g.robot);
            newFileInit();
            return true;
        } catch(Exception e) {
            System.out.println(e);
            return false;
        }
    }
    
    /**
     * Cleanup code on exit.
     */
    @Override
    public void exit() {
        currentTool = Tool.NONE;
        setKarelMap(null);
        setKarelRobot(null);
        updateUI();
        setPref();
        setVisible(false);
    }
    
    /**
     * Checks if map can be saved.
     * @return 
     */
    @Override
    public boolean isSavingAllowed() {
        return validateMap();
    }

    /*
     * Here below is auto generated code from NetBeans IDE 7.2.1
     */
    
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        splitPane = new javax.swing.JSplitPane();
        renderer = new karel.editors.mapeditor.MapEditorRenderer();
        controlsPanel = new javax.swing.JPanel();
        buttonDeleteObj = new javax.swing.JButton();
        buttonMakeWall = new javax.swing.JButton();
        buttonMakeStone = new javax.swing.JButton();
        buttonMakeExit = new javax.swing.JButton();
        buttonMakeKarel = new javax.swing.JButton();
        jMenuBar1 = new javax.swing.JMenuBar();
        menuFile = new javax.swing.JMenu();
        fileNewMap = new javax.swing.JMenuItem();
        sep1 = new javax.swing.JPopupMenu.Separator();
        fileOpenMap = new javax.swing.JMenuItem();
        fileSaveMap = new javax.swing.JMenuItem();
        fileSaveAsMap = new javax.swing.JMenuItem();
        jSeparator1 = new javax.swing.JPopupMenu.Separator();
        jMenuItem1 = new javax.swing.JMenuItem();
        menuTools = new javax.swing.JMenu();
        toolsDeleteObj = new javax.swing.JMenuItem();
        toolsMakeWall = new javax.swing.JMenuItem();
        toolsMakeStone = new javax.swing.JMenuItem();
        toolsMakeExit = new javax.swing.JMenuItem();
        toolsMakeKarel = new javax.swing.JMenuItem();
        menuEdit = new javax.swing.JMenu();
        editUndo = new javax.swing.JMenuItem();
        editRedo = new javax.swing.JMenuItem();
        menuGame = new javax.swing.JMenu();

        setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
        setTitle("Róbótinn Karel - Borðvinnsla");
        setIconImages(null);
        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowClosing(java.awt.event.WindowEvent evt) {
                formWindowClosing(evt);
            }
        });

        splitPane.setDividerLocation(150);
        splitPane.setEnabled(false);

        renderer.addMouseWheelListener(new java.awt.event.MouseWheelListener() {
            public void mouseWheelMoved(java.awt.event.MouseWheelEvent evt) {
                rendererMouseWheelMoved(evt);
            }
        });
        renderer.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                rendererMouseReleased(evt);
            }
        });

        javax.swing.GroupLayout rendererLayout = new javax.swing.GroupLayout(renderer);
        renderer.setLayout(rendererLayout);
        rendererLayout.setHorizontalGroup(
            rendererLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 475, Short.MAX_VALUE)
        );
        rendererLayout.setVerticalGroup(
            rendererLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 275, Short.MAX_VALUE)
        );

        splitPane.setRightComponent(renderer);

        controlsPanel.setLayout(new java.awt.GridLayout(5, 1));

        buttonDeleteObj.setFont(karel.util.FontLoader.getDefaultFont(karel.util.FontLoader.ButtonFontType,karel.util.FontLoader.ButtonFontSize));
        buttonDeleteObj.setIcon(new javax.swing.ImageIcon(getClass().getResource("/editor/eraser.png"))); // NOI18N
        buttonDeleteObj.setText("Eyða hlut");
        buttonDeleteObj.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                buttonDeleteObjActionPerformed(evt);
            }
        });
        controlsPanel.add(buttonDeleteObj);

        buttonMakeWall.setFont(karel.util.FontLoader.getDefaultFont(karel.util.FontLoader.ButtonFontType,karel.util.FontLoader.ButtonFontSize));
        buttonMakeWall.setIcon(new javax.swing.ImageIcon(getClass().getResource("/editor/wall.png"))); // NOI18N
        buttonMakeWall.setText("Veggur");
        buttonMakeWall.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                buttonMakeWallActionPerformed(evt);
            }
        });
        controlsPanel.add(buttonMakeWall);

        buttonMakeStone.setFont(karel.util.FontLoader.getDefaultFont(karel.util.FontLoader.ButtonFontType,karel.util.FontLoader.ButtonFontSize));
        buttonMakeStone.setIcon(new javax.swing.ImageIcon(getClass().getResource("/editor/rock.png"))); // NOI18N
        buttonMakeStone.setText("Kassi");
        buttonMakeStone.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                buttonMakeStoneActionPerformed(evt);
            }
        });
        controlsPanel.add(buttonMakeStone);

        buttonMakeExit.setFont(karel.util.FontLoader.getDefaultFont(karel.util.FontLoader.ButtonFontType,karel.util.FontLoader.ButtonFontSize));
        buttonMakeExit.setIcon(new javax.swing.ImageIcon(getClass().getResource("/editor/exit.png"))); // NOI18N
        buttonMakeExit.setText("Útgangur");
        buttonMakeExit.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                buttonMakeExitActionPerformed(evt);
            }
        });
        controlsPanel.add(buttonMakeExit);

        buttonMakeKarel.setFont(karel.util.FontLoader.getDefaultFont(karel.util.FontLoader.ButtonFontType,karel.util.FontLoader.ButtonFontSize));
        buttonMakeKarel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/editor/karel.png"))); // NOI18N
        buttonMakeKarel.setText("Karel");
        buttonMakeKarel.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                buttonMakeKarelActionPerformed(evt);
            }
        });
        controlsPanel.add(buttonMakeKarel);

        splitPane.setLeftComponent(controlsPanel);

        getContentPane().add(splitPane, java.awt.BorderLayout.CENTER);

        menuFile.setText("Skrá");

        fileNewMap.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_N, java.awt.event.InputEvent.CTRL_MASK));
        fileNewMap.setIcon(new javax.swing.ImageIcon(getClass().getResource("/common/new.png"))); // NOI18N
        fileNewMap.setText("Nýtt borð");
        fileNewMap.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                fileNewMapActionPerformed(evt);
            }
        });
        menuFile.add(fileNewMap);
        menuFile.add(sep1);

        fileOpenMap.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_O, java.awt.event.InputEvent.CTRL_MASK));
        fileOpenMap.setIcon(new javax.swing.ImageIcon(getClass().getResource("/common/open.png"))); // NOI18N
        fileOpenMap.setText("Opna borð");
        fileOpenMap.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                fileOpenMapActionPerformed(evt);
            }
        });
        menuFile.add(fileOpenMap);

        fileSaveMap.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_S, java.awt.event.InputEvent.CTRL_MASK));
        fileSaveMap.setIcon(new javax.swing.ImageIcon(getClass().getResource("/common/save.png"))); // NOI18N
        fileSaveMap.setText("Vista borð");
        fileSaveMap.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                fileSaveMapActionPerformed(evt);
            }
        });
        menuFile.add(fileSaveMap);

        fileSaveAsMap.setIcon(new javax.swing.ImageIcon(getClass().getResource("/common/saveas.png"))); // NOI18N
        fileSaveAsMap.setText("Vista borð sem ...");
        fileSaveAsMap.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                fileSaveAsMapActionPerformed(evt);
            }
        });
        menuFile.add(fileSaveAsMap);
        menuFile.add(jSeparator1);

        jMenuItem1.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_Q, java.awt.event.InputEvent.CTRL_MASK));
        jMenuItem1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/common/exit.png"))); // NOI18N
        jMenuItem1.setText("Loka");
        jMenuItem1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItem1ActionPerformed(evt);
            }
        });
        menuFile.add(jMenuItem1);

        jMenuBar1.add(menuFile);

        menuTools.setText("Tól");

        toolsDeleteObj.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_1, java.awt.event.InputEvent.CTRL_MASK));
        toolsDeleteObj.setIcon(new javax.swing.ImageIcon(getClass().getResource("/editor/eraser.png"))); // NOI18N
        toolsDeleteObj.setText("Eyða hlut");
        toolsDeleteObj.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                toolsDeleteObjActionPerformed(evt);
            }
        });
        menuTools.add(toolsDeleteObj);

        toolsMakeWall.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_2, java.awt.event.InputEvent.CTRL_MASK));
        toolsMakeWall.setIcon(new javax.swing.ImageIcon(getClass().getResource("/editor/wall.png"))); // NOI18N
        toolsMakeWall.setText("Veggur");
        toolsMakeWall.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                toolsMakeWallActionPerformed(evt);
            }
        });
        menuTools.add(toolsMakeWall);

        toolsMakeStone.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_3, java.awt.event.InputEvent.CTRL_MASK));
        toolsMakeStone.setIcon(new javax.swing.ImageIcon(getClass().getResource("/editor/rock.png"))); // NOI18N
        toolsMakeStone.setText("Kassi");
        toolsMakeStone.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                toolsMakeStoneActionPerformed(evt);
            }
        });
        menuTools.add(toolsMakeStone);

        toolsMakeExit.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_4, java.awt.event.InputEvent.CTRL_MASK));
        toolsMakeExit.setIcon(new javax.swing.ImageIcon(getClass().getResource("/editor/exit.png"))); // NOI18N
        toolsMakeExit.setText("Útgangur");
        toolsMakeExit.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                toolsMakeExitActionPerformed(evt);
            }
        });
        menuTools.add(toolsMakeExit);

        toolsMakeKarel.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_5, java.awt.event.InputEvent.CTRL_MASK));
        toolsMakeKarel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/editor/karel.png"))); // NOI18N
        toolsMakeKarel.setText("Karel");
        toolsMakeKarel.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                toolsMakeKarelActionPerformed(evt);
            }
        });
        menuTools.add(toolsMakeKarel);

        jMenuBar1.add(menuTools);

        menuEdit.setText("Breyta");

        editUndo.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_Z, java.awt.event.InputEvent.CTRL_MASK));
        editUndo.setIcon(new javax.swing.ImageIcon(getClass().getResource("/common/undo.png"))); // NOI18N
        editUndo.setText("Afturkalla");
        editUndo.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                editUndoActionPerformed(evt);
            }
        });
        menuEdit.add(editUndo);

        editRedo.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_Y, java.awt.event.InputEvent.CTRL_MASK));
        editRedo.setIcon(new javax.swing.ImageIcon(getClass().getResource("/common/redo.png"))); // NOI18N
        editRedo.setText("Endurkalla");
        editRedo.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                editRedoActionPerformed(evt);
            }
        });
        menuEdit.add(editRedo);

        jMenuBar1.add(menuEdit);

        menuGame.setIcon(new javax.swing.ImageIcon(getClass().getResource("/editor/karelplay.png"))); // NOI18N
        menuGame.setText("Opna borð í Leik");
        menuGame.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mousePressed(java.awt.event.MouseEvent evt) {
                menuGameMousePressed(evt);
            }
        });
        jMenuBar1.add(menuGame);

        setJMenuBar(jMenuBar1);

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void rendererMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_rendererMouseReleased
        Point p = renderer.mouseClicked(evt);
        performAction(p.x, p.y, SwingUtilities.isRightMouseButton(evt));
    }//GEN-LAST:event_rendererMouseReleased

    private void editUndoActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editUndoActionPerformed
        commandList.undo();
        updateUI();
    }//GEN-LAST:event_editUndoActionPerformed

    private void editRedoActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editRedoActionPerformed
        commandList.redo();
        updateUI();
    }//GEN-LAST:event_editRedoActionPerformed

    private void toolsMakeWallActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_toolsMakeWallActionPerformed
        selectTool(Tool.MAKEWALL);
    }//GEN-LAST:event_toolsMakeWallActionPerformed

    private void toolsDeleteObjActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_toolsDeleteObjActionPerformed
        selectTool(Tool.DELETE);
    }//GEN-LAST:event_toolsDeleteObjActionPerformed

    private void toolsMakeExitActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_toolsMakeExitActionPerformed
        selectTool(Tool.MAKEEXIT);
    }//GEN-LAST:event_toolsMakeExitActionPerformed

    private void toolsMakeKarelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_toolsMakeKarelActionPerformed
        selectTool(Tool.MAKEKAREL);
    }//GEN-LAST:event_toolsMakeKarelActionPerformed

    private void buttonDeleteObjActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonDeleteObjActionPerformed
        toolsDeleteObjActionPerformed(evt);
    }//GEN-LAST:event_buttonDeleteObjActionPerformed

    private void toolsMakeStoneActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_toolsMakeStoneActionPerformed
        selectTool(Tool.MAKESTONE);
    }//GEN-LAST:event_toolsMakeStoneActionPerformed

    private void buttonMakeWallActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonMakeWallActionPerformed
        toolsMakeWallActionPerformed(evt);
    }//GEN-LAST:event_buttonMakeWallActionPerformed

    private void buttonMakeStoneActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonMakeStoneActionPerformed
        toolsMakeStoneActionPerformed(evt);
    }//GEN-LAST:event_buttonMakeStoneActionPerformed

    private void buttonMakeExitActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonMakeExitActionPerformed
        toolsMakeExitActionPerformed(evt);
    }//GEN-LAST:event_buttonMakeExitActionPerformed

    private void buttonMakeKarelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonMakeKarelActionPerformed
        toolsMakeKarelActionPerformed(evt);
    }//GEN-LAST:event_buttonMakeKarelActionPerformed

    private void rendererMouseWheelMoved(java.awt.event.MouseWheelEvent evt) {//GEN-FIRST:event_rendererMouseWheelMoved
        Point p = renderer.mouseClicked(evt);
        performMouseWheelAction(p.x, p.y, evt.getUnitsToScroll() < 0);
    }//GEN-LAST:event_rendererMouseWheelMoved

    private void fileNewMapActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fileNewMapActionPerformed
        ed.newFile();
    }//GEN-LAST:event_fileNewMapActionPerformed

    private void fileOpenMapActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fileOpenMapActionPerformed
        ed.load();
    }//GEN-LAST:event_fileOpenMapActionPerformed

    private void fileSaveMapActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fileSaveMapActionPerformed
        ed.save();
    }//GEN-LAST:event_fileSaveMapActionPerformed

    private void fileSaveAsMapActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fileSaveAsMapActionPerformed
        ed.saveAs();
    }//GEN-LAST:event_fileSaveAsMapActionPerformed

    private void jMenuItem1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem1ActionPerformed
        ed.exit();
    }//GEN-LAST:event_jMenuItem1ActionPerformed

    private void formWindowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosing
        ed.exit();
    }//GEN-LAST:event_formWindowClosing

    private void menuGameMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_menuGameMousePressed
        if(validateMap()) {
            GameController.setGameContainer((GameContainer)ClassCopier.copyClass(new GameContainer(karelMap, karelRobot)));
            MainWin.map = ed.getFile();
            mainWin.getFocus();
        }
    }//GEN-LAST:event_menuGameMousePressed

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(MapEditor.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(MapEditor.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(MapEditor.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(MapEditor.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new MapEditor().setVisible(true);
            }
        });
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton buttonDeleteObj;
    private javax.swing.JButton buttonMakeExit;
    private javax.swing.JButton buttonMakeKarel;
    private javax.swing.JButton buttonMakeStone;
    private javax.swing.JButton buttonMakeWall;
    private javax.swing.JPanel controlsPanel;
    private javax.swing.JMenuItem editRedo;
    private javax.swing.JMenuItem editUndo;
    private javax.swing.JMenuItem fileNewMap;
    private javax.swing.JMenuItem fileOpenMap;
    private javax.swing.JMenuItem fileSaveAsMap;
    private javax.swing.JMenuItem fileSaveMap;
    private javax.swing.JMenuBar jMenuBar1;
    private javax.swing.JMenuItem jMenuItem1;
    private javax.swing.JPopupMenu.Separator jSeparator1;
    private javax.swing.JMenu menuEdit;
    private javax.swing.JMenu menuFile;
    private javax.swing.JMenu menuGame;
    private javax.swing.JMenu menuTools;
    private karel.editors.mapeditor.MapEditorRenderer renderer;
    private javax.swing.JPopupMenu.Separator sep1;
    private javax.swing.JSplitPane splitPane;
    private javax.swing.JMenuItem toolsDeleteObj;
    private javax.swing.JMenuItem toolsMakeExit;
    private javax.swing.JMenuItem toolsMakeKarel;
    private javax.swing.JMenuItem toolsMakeStone;
    private javax.swing.JMenuItem toolsMakeWall;
    // End of variables declaration//GEN-END:variables
}
